package kunsch.bexp.transform;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import kunsch.bexp.And;
import kunsch.bexp.Expression;
import kunsch.bexp.Not;
import kunsch.bexp.Or;
import kunsch.bexp.Variable;
import kunsch.bexp.util.Evaluator;
import kunsch.bexp.util.BExpUtil;

public class ShannonExpander
{


	public static Expression expand(List<Variable> variables, Expression expression)
	{
		List<Variable> orderedVariables = variables;

		List<Expression> expressionsToExpand = new ArrayList<Expression>();
		expressionsToExpand.add(expression);

		// develop given expression with given variable order
		for (Variable var : orderedVariables)
		{
			int size = expressionsToExpand.size();
			for (int i = 0; i < size; i++)
			{
				Expression current = expressionsToExpand.get(i);

				// evaluate function with variable = true
				HashMap<Variable, Boolean> values = new HashMap<Variable, Boolean>();
				values.put(var, true);
				Evaluator v = new Evaluator();
				Expression first = v.startEvaluation(current, values);

				// evaluate function with variable = false
				values.clear();
				values.put(var, false);

				Expression second = v.startEvaluation(current, values);

				expressionsToExpand.add(first);
				expressionsToExpand.add(second);

			}

			for (int i = 0; i < size; i++)
			{
				expressionsToExpand.remove(0);
			}

		}

		// AND variables to developed functions and OR them together
		for (int i = orderedVariables.size() - 1; i > -1; i--)
		{
			Variable currentVar = orderedVariables.get(i);
			int size = expressionsToExpand.size();

			for (int z = 0; z < size; z++)
			{
				List<Expression> list3 = new ArrayList<Expression>();
				
				Expression current = expressionsToExpand.get(z);
				
				List<Expression> list1 = new ArrayList<Expression>();
				list1.add(currentVar);
				list1.add(current);
				
				list3.add(new And(list1));
				
				z++;
				
				current = expressionsToExpand.get(z);
				
				List<Expression> list2 = new ArrayList<Expression>();
				list2.add(new Not(BExpUtil.copyExpression(currentVar)));
				list2.add(current);
				
				list3.add(new And(list2));
				
				expressionsToExpand.add(new Or(list3));

			}
			for (int x = 0; x < size; x++)
			{
				expressionsToExpand.remove(0);
			}

		}
		return expressionsToExpand.get(0);

	}
}
